package org.jfonia.musicxml.model;

import java.util.ArrayList;

import org.jfonia.harmony.ChordNotationStyle;
import org.jfonia.harmony.ChordType;
import org.jfonia.harmony.StandardChordNotationStyle;
import org.jfonia.musicxml.CodedMusicXMLImportException;
import org.jfonia.musicxml.HarmonyParser;
import org.w3c.dom.Node;

/**
 * class representing a harmony or chord as defined in MusicXML.
 * 
 * @author Wijnand
 */
// TODO: interpretation of ChordType must be factored out
public class Harmony extends Element implements MeasureElement
{
	static HarmonyParser harmonyParser = null;
	
	private PitchClass	rootPitchClass = null;
	//private String		kind = null;
	//private boolean 	kindIsShort = false;	// indicates whether kind is long-form or short-form (e.g. "minor-seventh" versus "m7")
	private PitchClass	bassPitchClass = null;	
	//private ArrayList<Alteration> alterationList = new ArrayList<Alteration>();
	private int			startTime;
	private int			duration = -1;
	private ChordType 	chordType = null;	// null indicates "no chord"

//	private static ResourceBundle chordTypeProperties = null;
	
	public static void setHarmonyParser(HarmonyParser hp)
	{
		harmonyParser = hp;
	}
	
	public Harmony(Node node) 
	{
		super(node);
	}
	
	
	public Harmony(Node node, PitchClass rootPitchClass, PitchClass bassPitchClass, int startTime, ChordType chordType)
	{
		super(node);
		// TODO Auto-generated constructor stub
		this.rootPitchClass = rootPitchClass;
		this.bassPitchClass = bassPitchClass;
		this.startTime = startTime;
		this.chordType = chordType;
	}

	public Harmony(Node node, PitchClass rootPitch, String kind, boolean kindIsShort, PitchClass bassPitch, ArrayList<Degree> alterationList, int startTime)
		throws CodedMusicXMLImportException
	{
		super(node);
		// TODO Auto-generated constructor stub
		this.rootPitchClass = rootPitch;
		// this.kind = kind;
		// this.kindIsShort = kindIsShort;
		this.bassPitchClass = bassPitch;
		// this.alterationList = alterationList;
		this.startTime = startTime;
		
		if (harmonyParser==null)
			throw new RuntimeException("HarmonyParser not set in Harmony");
		
		this.chordType = harmonyParser.determineType(kind, alterationList);
		//if (chordType == null)
		//	throw new MusicXMLException("HARMONY_UNKNOWN", kind);// TODO: report on alterationList too?
	}


	public void setChordType(ChordType chordType)
	{
		this.chordType = chordType;
	}



	public void setBassPitchClass(PitchClass bassPitch)
	{
		this.bassPitchClass = bassPitch;
	}

	public PitchClass getBassPitchClass()
	{
		return bassPitchClass;
	}

	public void setDuration(int duration)
	{
		this.duration = duration;
	}

	public int getDuration()
	{
		return duration;
	}

	public void setRootPitchClass(PitchClass rootPitch)
	{
		this.rootPitchClass = rootPitch;
	}

	public PitchClass getRootPitchClass()
	{
		return rootPitchClass;
	}

	public void setStartTime(int startTime)
	{
		this.startTime = startTime;
	}

	public int getStartTime()
	{
		return startTime;
	}
	
	public String toString() 
	{
		StringBuffer sb = new StringBuffer();
		sb.append(rootPitchClass.getStep());
		int a = rootPitchClass.getAlter();
		if (a==-1)
			sb.append('b');
		else if (a==1)
			sb.append('#');
		else if (a!=0)
			sb.append('?');
		sb.append(" ");
		
		ChordNotationStyle cns = new StandardChordNotationStyle();
		sb.append(cns.makeString(cns.makeTypeNotation(chordType)));
		
		if (bassPitchClass != null)
		{
			sb.append('/');
			sb.append(bassPitchClass.getStep());
			a = bassPitchClass.getAlter();
			if (a==-1)
				sb.append('b');
			else if (a==1)
				sb.append('#');
			else if (a!=0)
				sb.append('?');
			
		}
		
		sb.append(" [");
		sb.append(chordType.toString());
		sb.append("]");
		
		return sb.toString();
	}
	
	public ChordType getChordType()
	{
		return chordType;
	}

	
}
